// 1.没有原型的对象 完全的数据字典对象
let noPrototypeObj = Object.create(null, {
    name: {
        value: "noPrototypeObj"
    }
})

// 2.构造函数的实例化对象只会继承函数的prototype属性
let User = function() {}
User.__proto__.show = () => console.log(1)
let hd = new User()
// hd.show()

// 3.封顶时Object  .prototype,每个函数都会有一个prototype属性，
// 这个属性是一个指针，指向一个对象，记住只有函数才有,
// 并且通过bind()绑定的也没有。

// 4.字面量形式创建对象 相当于 构造函数创建

// 5.原型监测 {}.isPrototypeOf() 设置原型 Object.setPrototypeOf(a, b)
//                             设置a 为 b的原型

// 6. in 不止监测对象，还会监测原型链  {}.hasOwnProperty() 单纯检测对象，不会攀升原型链
let checkProtoObj = {}
checkProtoObj.__proto__.a = 1
console.log( "a" in checkProtoObj )
console.log( checkProtoObj.hasOwnProperty("a") )

// 7.借用原型链

// 8. __proto__  并不算属性，而是 getter setter 属性访问器
//              setter 会在 赋值为对象时成功
let hd2 = {
    name: "后盾人"
}
hd2.__proto__ = {
    show() {
        console.log(this.name)
    }
}
// 可以发现不能设置为非对象
hd2.__proto__ = 99
hd2.show()


// 9. 原型链继承
function SuperType1() {
    this.name = "father"
}

function SubType1() {
    this.name = "son"
}
// 创建SuperType的实例并赋值给SubType.prototype
SubType1.prototype = new SuperType1()
// 该方案缺点: 多个实例对引用类型的操作会被篡改，污染父元素

// 10.借用构造函数继承
function SuperType2() {
    this.name = "father"
}

function SubType2() {
    // 继承自SuperType，等同于复制父类的实例给子类
    SuperType2.call(this)
}

// 缺点：只能继承父类的实例属性和方法，不能继承原型属性方法；
//      无法实现复用，每个子类都有父类实例函数的副本，影响性能

// 11.组合继承
function SuperType3() {
    this.name = "father"
}
SuperType3.prototype.sayName = function () {
    alert(this.name)
}
function SubType3() {
    // 第二次调用SuperType
    SuperType2.call(this)
}

//第一次调用SuperType
SubType3.prototype = new SuperType3()
// 添加自己的构造方法、原型方法
SubType3.prototype.constructor = SubType3

// 缺点：第一次调用SuperType：给SubType.prototype写入属性
//      第二次调用SuperType：给instance写入属性
//      实例属性屏蔽了原型对象上的属性 使用子类创建实例，原型中会存在两份相同的属性/方法

// 12.原型式继承
function object(obj) {
    function F() {}
    F.prototype = obj
    return new F()
}
//对传入对象执行一次浅复制，将构造函数F的原型直接指向传入的对象
Object.create(obj)
//缺点：原型链继承多个实例的引用属性指向相同，存在篡改
//      无法传递参数

// 13.寄生式继承
function createAnother(original){
    let clone = object(original); // 通过调用 object() 函数创建一个新对象
    clone.sayHi = function(){  // 以某种方式来增强对象
        alert("hi");
    };
    return clone; // 返回这个对象
}
// 缺点同原型式继承

// 14.寄生组合式继承 最稳定的 class extends 的源码

// 前面讲过,组合继承是 JavaScript 最常用的继承模式; 不过, 它也有自己的不足. 组
// 合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数: 一次是在创建子类型原型的
// 时候, 另一次是在子类型构造函数内部. 寄生组合式继承就是为了降低调用父类构造函数的开销而出现的 .


function Sub() {
    SuperType3.call(this)
}

function inheritPrototype(subClass, superClass){
    let prototype = Object.create(superClass.prototype); // 创建对象，创建父类原型的一个副本，所以这里少调用了一次父类
    prototype.constructor = subClass;                    // 增强对象，弥补因重写原型而失去的默认的constructor 属性
    subClass.prototype = prototype;                      // 指定对象，将新创建的对象赋值给子类的原型
}

// 问题：无法调用Sub的原型方法
// 所以要为其添加子类私有方法
